package com.ludomancy.gamelib;

import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.io.InputStream;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.Stack;
import java.util.StringTokenizer;

public class Utils
{
	public static void drawTargetOutline(Graphics g, int x, int y, int w, int h)
	{
		int len = w/5;
		// top left
		g.drawLine(x, y, x + len, y);
		g.drawLine(x, y, x, y + len);
		// top right
		g.drawLine(x+w, y, x + w - len, y);
		g.drawLine(x+w, y, x + w, y + len);
		// bottom right
		g.drawLine(x+w, y+h, x + w - len, y+h);
		g.drawLine(x+w, y+h, x + w, y + h - len);
		// bottom left
		g.drawLine(x, y+h, x + len, y+h);
		g.drawLine(x, y+h, x , y + h - len);	
	}
	
	private static Stack translationStack = new Stack();
	private static Stack clipStack = new Stack();
	private static int translateX, translateY;
	
	public static void pushClipStack(Graphics g)
	{
		Rectangle area = g.getClipBounds();
		if(area == null)
		{
			g.setClip(0, 0, GameCanvas.screen.getWidth(), GameCanvas.screen.getHeight());
			area = g.getClipBounds();
		}
		clipStack.push(area);
	}
	
	private static Stack alphaStack = new Stack();
	
	public static void popAlpha(Graphics g)
	{
		AlphaComposite ac = (AlphaComposite)alphaStack.pop();
		Graphics2D g2 = (Graphics2D) g;
		g2.setComposite(ac);
	}
	
	public static void pushAlpha(Graphics g, float alpha)
	{
		pushAlpha(g, alpha, AlphaComposite.SRC_OVER);
	}
	
	public static void pushAlpha(Graphics g, float alpha, int operation)
	{
		Graphics2D g2 = (Graphics2D) g;
		alphaStack.push(g2.getComposite());
		try
		{
			float compose = alpha;
//			for (Iterator iterator = alphaStack.iterator(); iterator.hasNext();)
//			{
//				AlphaComposite a = (AlphaComposite) iterator.next();
//				compose *= a.getAlpha();
//			}
			AlphaComposite myAlpha = AlphaComposite.getInstance(operation,compose);
			g2.setComposite(myAlpha);
		}
		catch(Exception e)
		{
			System.out.println("Failed alpha. Value: "+alpha);
		}
	}
	
	public static void fillArea(Graphics g, int width, int height, ImageStrip strip, int frame)
	{
		fillArea(g, new Rectangle(0,0,width,height), strip, frame);
	}
	
	public static void fillArea(Graphics g, Rectangle area, ImageStrip strip, int frame)
	{
		int tileW = strip.frameWidth;
		int tileH = strip.frameHeight;
		int w = (area.width/tileW)+1;
		int h = (area.height/tileH)+1;
		pushClipStack(g);
		g.setClip(area.x, area.y, area.width, area.height);
		for (int y = 0; y < h; y++)
		{
			for (int x = 0; x < w; x++)
			{
				strip.paint(g, frame, area.x + x*tileW, area.y + y*tileH);
			}
		}
		popClipStack(g);
	}
	
	public static void pushAlphaDestination(Graphics g, float alpha)
	{
		Graphics2D g2 = (Graphics2D) g;
		alphaStack.push(g2.getComposite());
		AlphaComposite myAlpha = AlphaComposite.getInstance(
				AlphaComposite.DST_OVER,alpha);
		g2.setComposite(myAlpha);
	}

	public static void popClipStack(Graphics g)
	{
		Rectangle clip = (Rectangle) clipStack.pop();
		g.setClip(clip.x, clip.y, clip.width, clip.height);
	}
	
	public static void pushTranslation()
	{
		translationStack.push(new Point(translateX, translateY));
		translateX = translateY = 0;
	}
		
	public static void translate(Graphics g, int x, int y)
	{
		translateX += x;
		translateY += y;
		g.translate(x,y);
	}
	
	public static void popTranslation(Graphics g)
	{
		Point old = (Point) translationStack.pop();
		g.translate(-translateX, -translateY);
		translateX = old.x;
		translateY = old.y;
	}
	
    public static Point getCenterInRect(Point box, Rectangle area)
    {
    	int px = area.x + (area.width - box.x)/2;
    	int py = area.y + (area.height - box.y)/2;
    	Point ret = new Point(px,py);
    	return ret;
    }
    
    public static Point stringSize(Font font, String text)
    {
    	FontMetrics fm = GameCanvas.screen.getFontMetrics(font);
    	return new Point(fm.stringWidth(text), fm.getHeight());
    }
    
    public static void centerWindow(Window w)
	{
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension frameSize = w.getSize();

		if (frameSize.height > screenSize.height)
			frameSize.height = screenSize.height;
		if (frameSize.width > screenSize.width)
			frameSize.width = screenSize.width;
		w.setLocation((screenSize.width - frameSize.width) / 2,
				(screenSize.height - frameSize.height) / 2);
	}
    
    public static void drawImage(Graphics g, Image img, int x, int y, int anchor)
    {
    	drawImage(g, img, x, y, 0, 0, img.getWidth(null), img.getHeight(null), anchor );
    }
    
    public static void drawImage(Graphics g, Image img, int x, int y, int srcx, int srcy, int width, int height, int anchor)
    {
    	if((anchor & ANCHOR_HCENTER) != 0)
    	{
    		x-= width/2;
    	}
    	else
    	if((anchor & ANCHOR_RIGHT) != 0)
    	{
    		x-= width;
    	}
    	
    	if((anchor & ANCHOR_VCENTER) != 0)
    	{
    		y-= height/2;
    	}
    	else
    	if((anchor & ANCHOR_BOTTOM) != 0)
    	{
    		y-= height;
    	}
		g.drawImage(img,
                x,
                y,
                x+width,
                y+height,
                srcx,
                srcy,
                srcx+width,
                srcy+height,
                null);
    }
    
    public static void drawString(Graphics g, String text, int x, int y)
    {
    	drawString(g, text, x, y, 0);
    }
    
    public static final int ANCHOR_NONE = 0;
    public static final int ANCHOR_HCENTER = 1;
    public static final int ANCHOR_VCENTER = 2;
    public static final int ANCHOR_BOTTOM = 4;
	public static final int ANCHOR_RIGHT = 8;
    
    public static void drawString(Graphics g, String text, int x, int y, int anchor)
    {
    	int offset = g.getFontMetrics().getHeight() - g.getFontMetrics().getDescent();
    	if((anchor & ANCHOR_HCENTER) != 0)
    	{
    		x-= stringSize(g.getFont(), text).x/2;
    	}
    	if((anchor & ANCHOR_VCENTER) != 0)
    	{
    		y-= stringSize(g.getFont(), text).y/2;
    	}
    	else
    	if((anchor & ANCHOR_BOTTOM) != 0)
    	{
    		y-= stringSize(g.getFont(), text).y;
    	}
    	
    	g.drawString(text, x, offset + y);
    }
    
    public static void drawMultiline(Graphics g, String text, int width, int x, int y)
    {
    	if(text == null || text.length() == 0)
    	{
    		return;
    	}
    	Graphics2D g2d = (Graphics2D)g;
    	StringTokenizer sttok=new StringTokenizer(text,"\n\r\t",true);

    	while (sttok.hasMoreTokens())
    	{
			// Get iterator for string
    		String token = sttok.nextToken();
	    	AttributedString as = new AttributedString(token);
	    	as.addAttribute(TextAttribute.FONT, g.getFont());
			AttributedCharacterIterator characterIterator = as.getIterator();
			// Get font context from graphics
			FontRenderContext fontRenderContext = g2d.getFontRenderContext();

			// Create measurer
			LineBreakMeasurer measurer = new LineBreakMeasurer(characterIterator, fontRenderContext);
			while (measurer.getPosition() < characterIterator.getEndIndex() && !token.equals("\n"))
			{
				// Get line
				TextLayout textLayout = measurer.nextLayout(width);
				// Move down to baseline
				y += textLayout.getAscent();
				// Draw line
				textLayout.draw(g2d, x, y);
				// Move down to top of next line
				y += textLayout.getDescent() + textLayout.getLeading();
			}
    	}
    }
    
    public static void drawStringCentered(Graphics g, String text, Rectangle area)
    {
    	drawString(g, text, area.x + area.width/2, area.y + area.height/2, ANCHOR_HCENTER | ANCHOR_VCENTER);
    }
    
    public static void drawStringVerticallyCentered(Graphics g, String text, int x, int centerY)
    {
    	// Get measures needed to center the message
		FontMetrics fm = g.getFontMetrics();

		// How far above the baseline can the font go?
		int ascent = fm.getMaxAscent();

		// How far below the baseline?
		int descent = fm.getMaxDescent();

		// Use the vertical height of this font to find
		// the vertical starting coordinate
		int msgY = centerY - descent / 2 + ascent / 2;

		g.drawString(text, x, msgY-1);
    }
    
    public static Font loadFont(String path) throws Exception
    {
    	Font ret;
		InputStream fontStream = GameApplet.gameAppletInstance.getClass().getResourceAsStream(path);
		ret = java.awt.Font.createFont( java.awt.Font.TRUETYPE_FONT, fontStream  );
		fontStream.close();
		return ret;
    }
    
}
